/*
 * ScenarioMethodInvoker.java
 * 
 * Created on 21.05.2007, 19:01:54
 * 
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package logrus.beanmock.invoker;

import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import logrus.beanmock.exception.NotMatchedMethodInvocationException;

import org.apache.commons.collections.Predicate;

/**
 * 
 * @author serge
 */
public class ScenarioMethodInvoker implements MethodInvoker {

    private CounterAccessorImpl counters = new CounterAccessorImpl();

    private MethodInvocationInfo[] infos;

    private Map<Method, Integer> statistics = new HashMap<Method, Integer>();

    public ScenarioMethodInvoker(MethodInvocationInfo... infos) {
        this.infos = infos;
    }

    private MethodInvocationInfo getInfo(Predicate predicate) {
        for (MethodInvocationInfo info : infos) {
            if (predicate.evaluate(info)) {
                return info;
            }
        }
        return null;
    }

    public MethodInvokerStatistics getStatistics() {
        return new MethodInvokerStatistics(Collections.unmodifiableMap(statistics));
    }

    public Object invoke(Object target, Method method, Object... args) throws Throwable {
        registerInvocation(method);

        Predicate targetPredicate = new MethodInvocationInfoPredicate(target, method, counters);

        MethodInvocationInfo info = getInfo(targetPredicate);
        if (info == null) {
            throw new NotMatchedMethodInvocationException();
        }

        Counter counter = counters.getCounter(info);
        counter.inc();

        return info.getInvoker().invoke(target, method, args);
    }

    private void registerInvocation(final Method method) {
        Integer count = statistics.get(method);
        if (count != null) {
            count = Integer.valueOf(count.intValue() + 1);
        } else {
            count = Integer.valueOf(1);
        }
        statistics.put(method, count);
    }

}
